package org.example.security.util;

import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import org.example.security.autoconfiguration.SecurityProperties;
import org.example.security.entity.User;

import java.util.*;

/**
 * jwt工具类
 * @author zuoyi
 */
public class JwtTokenUtil {

    private SecurityProperties securityProperties;

    public JwtTokenUtil(SecurityProperties securityProperties) {
        this.securityProperties = securityProperties;
    }

    private static final String CLAIM_KEY_UPDATE_TIME = "update_time";


    /**
     * 生成token
     *
     * @param jsonUserDetails json格式化后的userDetails
     * @return String
     */
    public String generateToken(String jsonUserDetails) {
        JwtBuilder jwtBuilder = Jwts.builder();
        String token = jwtBuilder
                // header
                .setHeaderParam("type","jwt")
                .setHeaderParam("alg",securityProperties.getJwt().getSignatureAlgorithm().getValue())
                // payload
                .claim(securityProperties.getJwt().getLoginUserInfoKey(),jsonUserDetails)
                .setExpiration(generateExpirationDate())
                .setId(UUID.randomUUID().toString())
                // 签名
                .signWith(securityProperties.getJwt().getSignatureAlgorithm(),securityProperties.getJwt().getSecret())
                .compact();
        return token;
    }

    /**
     * 生成token
     *
     * @param payload 载荷
     * @return String
     */
    public String generateToken(Map<String,Object> payload) {
        return Jwts.builder()
                .setClaims(payload)
                .setExpiration(generateExpirationDate())
                .signWith(securityProperties.getJwt().getSignatureAlgorithm(), securityProperties.getJwt().getSecret())
                .compact();
    }


    /**
     * 验证token是否有效,有效返回true, 无效返回false
     * @param token
     * @return
     */
    public boolean validateToken(String token){
        if (token == null || token.equals("") || !token.startsWith(securityProperties.getJwt().getBearer())) {
            return false;
        }

        User userInfoFromToken = getUserInfoFromToken(token);
        if (userInfoFromToken == null) {
            return false;
        }

        String realToken = token.substring(securityProperties.getJwt().getBearer().length());
        if (isTokenExpired(realToken)) {
            return false;
        }
        return true;
    }


    /**
     * 判断token是否可以被刷新
     * @param token
     * @return
     */
    public boolean canRefresh(String token){
        if (token != null && token.startsWith(securityProperties.getJwt().getBearer())) {
            String realToken = token.substring(securityProperties.getJwt().getBearer().length());
            return !isTokenExpired(realToken);
        }
        return false;
    }

    /**
     * 刷新token
     * @param token
     * @return
     */
    public String refreshToken(String token){
        if (token != null && token.startsWith(securityProperties.getJwt().getBearer())) {
            token = token.substring(securityProperties.getJwt().getBearer().length());
        }
        Claims claims = getClaimsFormToken(token);
        claims.put(CLAIM_KEY_UPDATE_TIME,new Date());
        return generateToken(claims);
    }

    /**
     * 判断token是否失效
     * @param token
     * @return
     */
    private boolean isTokenExpired(String token) {
        Date expireDate = getExpiredDateFromToken(token);
        return expireDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     * @param token
     * @return
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFormToken(token);
        return claims.getExpiration();
    }

    /**
     * 从token中获取登录用户信息
     */
    public User getUserInfoFromToken(String token) {
        if (token != null && token.startsWith(securityProperties.getJwt().getBearer())) {
            String realToken = token.substring(securityProperties.getJwt().getBearer().length());
            Claims payload = getClaimsFormToken(realToken);
            if (payload == null) {
                return null;
            }
            String jsonUserDetails = (String)payload.get(securityProperties.getJwt().getLoginUserInfoKey());
            return JSONUtil.toBean(jsonUserDetails, User.class);
        }
        return null;
    }

    /**
     * 从token中获取荷载
     * @param token
     * @return
     */
    private Claims getClaimsFormToken(String token) {
        if (token != null && token.startsWith(securityProperties.getJwt().getBearer())) {
            token = token.substring(securityProperties.getJwt().getBearer().length());
        }
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(securityProperties.getJwt().getSecret())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            return null;
        }
        return claims;
    }

    /**
     * 生成token失效时间
     * @return Date
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + securityProperties.getJwt().getExpiration() * 60 * 1000);
    }
}
